//// ----------------
/*
 * Name :   Tog
 * Author : Liangliang Zheng (jsPop)
 * Date :   2011-5-12
 *
 * basic usage:
 * Tog('table')
 * .tr('.data_row')
 * .td().cont('something here').attr('tdId', 23)
 * .td('/').cont('something else')
 * .html()
 *
 * output:
 * <table>
 *  <tr class='data_row'>
 *      <td tdId='23'>something here</td>
 *      <td>something else</td>
 *  </tr>
 * </table>
 *
 * Special thanks to Kevin van and others for providing htmlentities util
 * for my raw() function
 *
 */

;
(function(){

    function  htmlentities(string, quote_style) {
        // Convert all applicable characters to HTML entities
        //
        // version: 1009.2513
        // discuss at: http://phpjs.org/functions/htmlentities    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
        // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
        // +   improved by: nobbler
        // +    tweaked by: Jack
        // +   bugfixed by: Onno Marsman    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
        // +    bugfixed by: Brett Zamir (http://brett-zamir.me)
        // +      input by: Ratheous
        // -    depends on: get_html_translation_table
        // *     example 1: htmlentities('Kevin & van Zonneveld');    // *     returns 1: 'Kevin &amp; van Zonneveld'
        // *     example 2: htmlentities("foo'bar","ENT_QUOTES");
        // *     returns 2: 'foo&#039;bar'
        var hash_map = {}, symbol = '', tmp_str = '', entity = '';
        if(typeof(string)== 'undefined' || string == null) return null;
        tmp_str = string.toString();
        if (false === (hash_map = this.get_html_translation_table('HTML_ENTITIES', quote_style))) {
            return false;
        }
        hash_map["'"] = '&#039;';
        for (symbol in hash_map) {
            entity = hash_map[symbol];
            tmp_str = tmp_str.split(symbol).join(entity);
        }
        return tmp_str;
    }

    function get_html_translation_table (table, quote_style) {
        // http://kevin.vanzonneveld.net
        // +   original by: Philip Peterson
        // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
        // +   bugfixed by: noname
        // +   bugfixed by: Alex
        // +   bugfixed by: Marco
        // +   bugfixed by: madipta
        // +   improved by: KELAN
        // +   improved by: Brett Zamir (http://brett-zamir.me)
        // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
        // +      input by: Frank Forte
        // +   bugfixed by: T.Wild
        // +      input by: Ratheous
        // %          note: It has been decided that we're not going to add global
        // %          note: dependencies to php.js, meaning the constants are not
        // %          note: real constants, but strings instead. Integers are also supported if someone
        // %          note: chooses to create the constants themselves.
        // *     example 1: get_html_translation_table('HTML_SPECIALCHARS');
        // *     returns 1: {'"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;'}

        var entities = {}, hash_map = {}, decimal = 0, symbol = '';
        var constMappingTable = {}, constMappingQuoteStyle = {};
        var useTable = {}, useQuoteStyle = {};

        // Translate arguments
        constMappingTable[0]      = 'HTML_SPECIALCHARS';
        constMappingTable[1]      = 'HTML_ENTITIES';
        constMappingQuoteStyle[0] = 'ENT_NOQUOTES';
        constMappingQuoteStyle[2] = 'ENT_COMPAT';
        constMappingQuoteStyle[3] = 'ENT_QUOTES';

        useTable       = !isNaN(table) ? constMappingTable[table] : table ? table.toUpperCase() : 'HTML_SPECIALCHARS';
        useQuoteStyle = !isNaN(quote_style) ? constMappingQuoteStyle[quote_style] : quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT';

        if (useTable !== 'HTML_SPECIALCHARS' && useTable !== 'HTML_ENTITIES') {
            throw new Error("Table: "+useTable+' not supported');
        // return false;
        }

        entities['38'] = '&amp;';
        if (useTable === 'HTML_ENTITIES') {
            entities['160'] = '&nbsp;';
            entities['161'] = '&iexcl;';
            entities['162'] = '&cent;';
            entities['163'] = '&pound;';
            entities['164'] = '&curren;';
            entities['165'] = '&yen;';
            entities['166'] = '&brvbar;';
            entities['167'] = '&sect;';
            entities['168'] = '&uml;';
            entities['169'] = '&copy;';
            entities['170'] = '&ordf;';
            entities['171'] = '&laquo;';
            entities['172'] = '&not;';
            entities['173'] = '&shy;';
            entities['174'] = '&reg;';
            entities['175'] = '&macr;';
            entities['176'] = '&deg;';
            entities['177'] = '&plusmn;';
            entities['178'] = '&sup2;';
            entities['179'] = '&sup3;';
            entities['180'] = '&acute;';
            entities['181'] = '&micro;';
            entities['182'] = '&para;';
            entities['183'] = '&middot;';
            entities['184'] = '&cedil;';
            entities['185'] = '&sup1;';
            entities['186'] = '&ordm;';
            entities['187'] = '&raquo;';
            entities['188'] = '&frac14;';
            entities['189'] = '&frac12;';
            entities['190'] = '&frac34;';
            entities['191'] = '&iquest;';
            entities['192'] = '&Agrave;';
            entities['193'] = '&Aacute;';
            entities['194'] = '&Acirc;';
            entities['195'] = '&Atilde;';
            entities['196'] = '&Auml;';
            entities['197'] = '&Aring;';
            entities['198'] = '&AElig;';
            entities['199'] = '&Ccedil;';
            entities['200'] = '&Egrave;';
            entities['201'] = '&Eacute;';
            entities['202'] = '&Ecirc;';
            entities['203'] = '&Euml;';
            entities['204'] = '&Igrave;';
            entities['205'] = '&Iacute;';
            entities['206'] = '&Icirc;';
            entities['207'] = '&Iuml;';
            entities['208'] = '&ETH;';
            entities['209'] = '&Ntilde;';
            entities['210'] = '&Ograve;';
            entities['211'] = '&Oacute;';
            entities['212'] = '&Ocirc;';
            entities['213'] = '&Otilde;';
            entities['214'] = '&Ouml;';
            entities['215'] = '&times;';
            entities['216'] = '&Oslash;';
            entities['217'] = '&Ugrave;';
            entities['218'] = '&Uacute;';
            entities['219'] = '&Ucirc;';
            entities['220'] = '&Uuml;';
            entities['221'] = '&Yacute;';
            entities['222'] = '&THORN;';
            entities['223'] = '&szlig;';
            entities['224'] = '&agrave;';
            entities['225'] = '&aacute;';
            entities['226'] = '&acirc;';
            entities['227'] = '&atilde;';
            entities['228'] = '&auml;';
            entities['229'] = '&aring;';
            entities['230'] = '&aelig;';
            entities['231'] = '&ccedil;';
            entities['232'] = '&egrave;';
            entities['233'] = '&eacute;';
            entities['234'] = '&ecirc;';
            entities['235'] = '&euml;';
            entities['236'] = '&igrave;';
            entities['237'] = '&iacute;';
            entities['238'] = '&icirc;';
            entities['239'] = '&iuml;';
            entities['240'] = '&eth;';
            entities['241'] = '&ntilde;';
            entities['242'] = '&ograve;';
            entities['243'] = '&oacute;';
            entities['244'] = '&ocirc;';
            entities['245'] = '&otilde;';
            entities['246'] = '&ouml;';
            entities['247'] = '&divide;';
            entities['248'] = '&oslash;';
            entities['249'] = '&ugrave;';
            entities['250'] = '&uacute;';
            entities['251'] = '&ucirc;';
            entities['252'] = '&uuml;';
            entities['253'] = '&yacute;';
            entities['254'] = '&thorn;';
            entities['255'] = '&yuml;';
        }

        if (useQuoteStyle !== 'ENT_NOQUOTES') {
            entities['34'] = '&quot;';
        }
        if (useQuoteStyle === 'ENT_QUOTES') {
            entities['39'] = '&#39;';
        }
        entities['60'] = '&lt;';
        entities['62'] = '&gt;';


        // ascii decimals to real symbols
        for (decimal in entities) {
            symbol = String.fromCharCode(decimal);
            hash_map[symbol] = entities[decimal];
        }

        return hash_map;
    }

    var exp_tag = /^[a-zA-Z][\w_]*/;
    var exp_tagExtra = /([\.\#\$\&\?])([\w_-]*)/g;

    function tag_clone(t){
        var newT = {
            cls: {}
        }
        if('tag' in t) newT.tag = t.tag;
        if('name' in t) newT.name = t.name;
        if('id' in t) newT.id = t.id;
        if('type' in t) newT.type = t.type;
        if('anc' in t) newT.anc = t.anc;

        for(var i in t.cls){
            newT.cls[i] = 1;
        }
        return newT
    }

    var cacheTagStr = {
        length :0
    };
    var tagCacheNumber = 299;
    function tag_putCacheTagStr(tagStr, t){
        cacheTagStr[tagStr] = tag_clone(t);
        cacheTagStr.length ++;
        if(cacheTagStr.length > tagCacheNumber){ // cache 300 tag strs
            var j = 0;
            for(var i in cacheTagStr){
                if(j++ > 0){
                    cacheTagStr.length --;
                    delete cacheTagStr[i];
                    return;
                }
            }
        }
    }
    function tag_getCacheTagStr(tagStr){
        if(tagStr in cacheTagStr){
            return tag_clone(cacheTagStr[tagStr]);
        } else{
            return null;
        }
    }
    function tag_pushTagExtra(type, content, t){
        switch(type){
            case '.':
                t.cls[content] = 1;
                break;
            case '#':
                t.id = content;
                break;
            case '&':
                t.type = content;
                break;
            case '$':
                t.name = content;
                break;
            case '?':
                t.anc = content;
                break;
        }
    }

    /**
     * <pre>
     * tagStr - table#some_id.some_class$some_name&some_type
     * return the object
     * {tag, name, id, cls:{}, type}
     *
     */
    function tag_parseTagStrUnit(tagStr){
        var t = tag_getCacheTagStr(tagStr);
        if(t != null){
            return t;
        }
        var res = exp_tag.exec(tagStr);
        if(res == null){
            t = {
                cls: {}
            };
        } else {
            t = {
                tag: res['0'],
                cls: {}
            };
        }


        var lastType = [];
        while(true){
            res = exp_tagExtra.exec(tagStr);
            if(res == null){
                tag_putCacheTagStr(tagStr, t);
                return t;
            }
            if(res['2'] != ''){
                if(lastType.length > 0){
                    for(var i = 0; i < lastType.length; i ++ ){
                        tag_pushTagExtra(lastType[i], res['2'], t);
                    }
                    lastType = [];
                }
                tag_pushTagExtra(res['1'], res['2'], t);
            } else {
                lastType.push(res['1']);
            }
        }
    }

    var html_emptyTags ={
        'br':1,
        'hr':1,
        'meta':1,
        'link':1,
        'base':1,
        'img':1,
        'embed':1,
        'param':1,
        'area':1,
        'col':1,
        'input':1
    }
    function htmlIndentation(level){
        var str = '  ';
        return new Array( level ).join( str );
    }

    var bIndentation = true;
    var bNewline = true;
    _tog = function(tagStr){
        this.t = tag_parseTagStrUnit(tagStr);
        this._parent = null;
        this.content = [];
    }

    var func_extended = null;

    _tog.prototype = {
        _copyIds: function(ids){
            var root = this;
            for(var i in ids){
                if(ids.hasOwnProperty(i)){
                    root._ids[i] = ids[i];
                }
            }
        },
        close: function(tagStr){
            var tagObj = tag_parseTagStrUnit(tagStr);
            while(true){
                if(this._isMatchCond(tagObj)){
                    this.curr = this.curr._parent;
                    return this;
                }
                if(this.curr._parent == null){
                    return this;
                }
                this.curr = this.curr._parent;
            }
            return this;
        },
        up: function(tagStr){
            if(typeof tagStr == 'undefined'){
                if(this.curr._parent != null){
                    this.curr = this.curr._parent;
                }
            } else if(typeof tagStr == 'string'){
                var tagObj = tag_parseTagStrUnit(tagStr);
                while(true){
                    if(this._isMatchCond(tagObj) || this.curr._parent == null){
                        return this;
                    }
                    this.curr = this.curr._parent;
                }
            } else {
                for(var i = 0; i < tagStr && this.curr._parent != null; i++){
                    this.curr = this.curr._parent;
                }
            }
            return this;
        },
        _isMatchCond: function(tagObj){
            var t = this.curr.t;
            if('tag' in tagObj && (!('tag' in t) || tagObj.tag != t.tag)){
                return false;
            }
            if('id' in tagObj && (!('id' in t) || tagObj.id != t.id)){
                return false;
            }
            if('name' in tagObj && (!('name' in t) || tagObj.name != t.name)){
                return false;
            }
            if('type' in tagObj && (!('type' in t) || tagObj.type != t.type)){
                return false;
            }
            for(var i in tagObj.cls){
                if(tagObj.cls.hasOwnProperty(i) && !(i in t.cls)){
                    return false;
                }
            }
            return true;
        }
        ,
        Tog: function(fullTagStr, attrs, content){
            // the / is for separating the closing tag string and the new tag string
            if(typeof fullTagStr == 'string'){
                var tagStrs = fullTagStr.split('/');
            } else {
                tagStrs = fullTagStr;
            }
            if(tagStrs.length > 1){
                var closeTagStr = tagStrs[0];
                if(closeTagStr.replace(/^ +$/, '') == ''){
                    this.up();
                } else {
                    this.close(closeTagStr);
                }
                // gonna close the tag

                var newTagStr = tagStrs[1];
            } else {
                newTagStr = tagStrs[0];
            }
            var _this = this.curr;

            // creating a new tag and append to the current tag
            // the current curr will be replaced to the the new tag
            var newTag = new _tog(newTagStr);
            newTag._parent = _this;
            newTag._root = this;
            this.curr = newTag;
            if('id' in newTag.t){
                this._ids[newTag.t.id] = newTag;
            }
            if(attrs) this.attr(attrs);
            if(content){
                if(typeof content == 'object' && !content._root){
                    this.cont.apply(this, content);
                } else {
                    this.cont(content);
                }
            }
            _this.content.push(newTag);
            return this;
        },
        astr: function(attr1, attr2){
            var t= this.curr.t;
            for(var i = 0; i < arguments.length; i++){
                var attr = arguments[i];
                // if the input is a string, simply put it in attrStr
                if(!t.attrStr){
                    t.attrStr = [];
                }
                t.attrStr.push(attr);
            }
            return this;
        },
        attr: function(attr, value){
            var t= this.curr.t;
            // if the input is an object
            // we will treat every key in the object as the name of the attribute name
            if(!('attrs' in t)){
                t.attrs = {};
            }
            // if attr is a string, regard it as attr name
            if(typeof attr == 'string'){
                t.attrs[attr] = value;
            } else {
                for(var attrName in attr){
                    if(attr.hasOwnProperty(attrName)){
                        t.attrs[attrName] = attr[attrName];
                    }
                }
            }
            return this;
        },
        removeAttr:function(key){
            var t = this.curr.t;
            if(typeof key == 'object'){
                for(var k in key){
                    if(key.hasOwnProperty(k)){
                        delete t.attrs[key[k]];
                    }
                }
            } else {
                delete t.attrs[key];
            }
            return this;
        },
        cont: function(content1, content2){
            var curr = this.curr;
            for(var i = 0; i < arguments.length; i++){
                var content = arguments[i];
                curr.content.push(content);
                // if the content is a tag object
                // configure it and join the ids into the root tag object
                if(typeof content == 'object' && '_root' in content){
                    content._parent = this.curr;
                    this._copyIds(content._ids);
                    content._root = this;
                }
            }
            return this;
        },
        raw:function(content1, content2){
            var curr = this.curr;
            for(var i = 0; i < arguments.length; i++){
                var content = arguments[i];
                curr.content.push(htmlentities(content));
            }
            return this;
        },
        sstr: function(style1, style2){
            var t= this.curr.t;
            for(var i = 0; i < arguments.length; i++){
                var style = arguments[i];
                if(!t.styleStr){
                    t.styleStr = [];
                }
                t.styleStr.push(style);
            }
            return this;
        },
        style: function(style, value){
            var t= this.curr.t;
            // if the input is an object
            // we will treat every key in the object as the name of the style name
            if(!t.styles){
                t.styles = {};
            }
            // if the input is a string, simply put it in styleStr
            if(typeof style == 'string'){
                t.styles[style] = value;
            } else {
                for(var styleName in style){
                    if(style.hasOwnProperty(styleName)){
                        t.styles[styleName] = style[styleName];
                    }
                }
            }
            return this;
        },
        cls: function(clsStr){
            var t = this.curr.t;
            var classes = clsStr.split(/\s+/);
            for(var i in classes){
                if(classes.hasOwnProperty(i) && classes[i] != ''){
                    t.cls[classes[i]] = 1;
                }
            }
            return this;
        },
        id: function(id){
            delete this._ids[this.t.id];
            this.t.id = id;
            this._ids[id] = this;
            return this;
        },
        name: function(name){
            this.curr.t.name = name;
            return this;
        },
        type: function (type){
            this.curr.t.type = type;
            return this;
        },
        emp:function(fullTagStr){
            if(!fullTagStr) fullTagStr = ' ';
            this.Tog(fullTagStr);
            this.curr._emp = 1;
            return this;
        },
        html: function(indent, newline){
            // if there is indentation for the html generated
            if(typeof indent == 'undefined') indent = bIndentation;
            // if the generated html is armed with new lines
            if(typeof newline == 'undefined') newline = bNewline;

            var htmlText = [];
            this._htmlStr(indent, newline, 0, htmlText);
            return htmlText.join('');
        },
        _htmlStr: function(indent, newline, level, h){
            if(!('_emp' in this)){
                var t = this.t;
                h[h.length] = htmlIndentation(level);
                h[h.length] = '<';
                h[h.length] = t.tag;
                if('id' in t){
                    h[h.length] = ' id="';
                    h[h.length] = t.id;
                    h[h.length] = '"';
                }
                if('name' in t){
                    h[h.length] = ' name="';
                    h[h.length] = t.name;
                    h[h.length] = '"';
                }
                if('type' in t){
                    h[h.length] = ' type="';
                    h[h.length] = t.type;
                    h[h.length] = '"';
                }
                var hasCls = false;
                for(var key in t.cls){
                    hasCls = true;
                    break;
                }
                if(hasCls){
                    h[h.length] = ' class="';
                    var f = true;
                    for(var key in t.cls){
                        if(t.cls.hasOwnProperty(key)){
                            if(f) f = false;
                            else h[h.length] = ' ';
                            h[h.length] = key;
                        }
                    }
                    h[h.length] = '"';
                }
                if('attrStr' in t){
                    h[h.length] = ' ';
                    h[h.length] = t.attrStr.join(' ');
                }
                if('attrs' in t){
                    f = true;
                    for(key in t.attrs){
                        if(t.attrs.hasOwnProperty(key)){
                            if(f) {
                                h[h.length] = ' ';
                                f = false;
                            } else {
                                h[h.length] = '" ';
                            }
                            h[h.length] = key;
                            h[h.length] = '="';
                            h[h.length] = t.attrs[key];
                        }
                    }
                    h[h.length] = '"';
                }
                if('styleStr' in t || 'styles' in t){
                    h[h.length] = ' style="';
                    if('styleStr' in t){
                        h[h.length] = t.styleStr.join(';');
                        h[h.length] = ';';
                    }
                    if('styles' in t){
                        for(key in t.styles){
                            if(t.styles.hasOwnProperty(key)){
                                h[h.length] = key;
                                h[h.length] = ':';
                                h[h.length] = t.styles[key];
                                h[h.length] = ';';
                            }
                        }
                    }
                    h[h.length] = '"';
                }
                if(t.tag in html_emptyTags){
                    h[h.length] = '/>';
                    if(newline) h[h.length] = '\n';
                    return;
                } else {
                    h[h.length] = '>';
                }
            // end of if emp not in t
            }
            var content = this.content;
            for(var i = 0; i < content.length; i++){
                if(typeof content[i] == 'object' && '_htmlStr' in content[i]){
                    if(newline && h.length > 0 && h[h.length-1] != '\n' && !('_emp' in content[i])) h[h.length] = '\n';
                    content[i]._htmlStr(indent, newline, level+1, h)
                } else {
                    h[h.length] = content[i];
                }
            }
            if(!('_emp' in this)){
                if(h[h.length-1] == '\n') h[h.length] = htmlIndentation(level);
                h[h.length] = '</';
                h[h.length] = t.tag;
                h[h.length] = '>';
                if(newline) h[h.length] = '\n';
            }
        },
        setConfig: function(config){
            if('indent' in config){
                bIndentation = config.indent;
            }
            if('newline' in config){
                bNewline = config.newline;
            }
            if('cacheNum' in config){
                tagCacheNumber = config.cacheNum;
            }
            return this;
        },
        get: function(id){
            if(id in this._ids){
                this.curr = this._ids[id];
                return this;
            } else {
                return this;
            }
        },
        clearExtra: function(extra){
            var t = this.curr.t;
            if(extra.indexOf('c') != -1){
                t.cls = {};
            }
            if(extra.indexOf('i') != -1){
                delete t.id;
            }
            if(extra.indexOf('t') != -1){
                delete t.type;
            }
            if(extra.indexOf('n') != -1){
                delete t.name
            }
            if(extra.indexOf('a')){
                delete t.attrStr;
                delete t.attrs;
            }
            if(extra.indexOf('s')){
                delete t.styleStr;
                delete t.styles;
            }
            return this;
        },
        clear: function(id){
            if(typeof id == 'undefined'){
                target = this.curr;
            } else if(id in this._root._ids){
                var target = this._root._ids[id];
            } else {
                return this;
            }
            var content = target.content;
            for(var i in content){
                if(content.hasOwnProperty(i)){
                    if(typeof content[i] == 'object' && 'clear' in content[i]){
                        content[i].clear();
                        if(content[i].t.id){
                            delete content[i]._root._ids[content[i].t.id];
                        }
                    }
                }
            }
            target.content = {};
            this.curr = target;
            return this;
        }
        // ------------------ EXTENTION FUNCS
        ,
        _specTog: function(fullTagStr, tag, attrs, content){
            if(!fullTagStr) fullTagStr = '';
            var s = fullTagStr.split('/');
            if(s.length > 1){
                return this.Tog([s[0], [tag, s[1]].join('')], attrs, content);
            } else {
                return this.Tog([[tag, s[0]].join('')], attrs, content);
            }
        },
        _extendFunc:function(func, extra, prot){
            if(func in func_extended['__basic__']){
                // stop the script from pouring functions into core prop
                throw new Error('cannot extend funcs to core prop');
            }
            prot[func] = extra;
        },
        extendFuncs: function(funcs, group){
            if(group == '__basic__'){
                // stop the script from pouring functions into core prop
                throw new Error('cannot extend funcs to __basic__');
            }
            if(func_extended == null){
                func_extended = {
                    '__basic__': {
                        't':1,
                        '_parent':1,
                        '_root':1,
                        '_ids':1,
                        '_emp':1,
                        'content':1,
                        'curr':1
                    }
                };
                var basic = func_extended['__basic__']
                for(var i in _tag.prototype){
                    basic[i] = 1;
                }
            }
            // group it to the default group '_', if no group id is provided
            if(!group) group = '_';
            if(!func_extended[group]) func_extended[group] = {};
            // key is the prop, val is the function
            for(var key in funcs){
                if(funcs.hasOwnProperty(key)){
                    this._extendFunc(key, funcs[key], _tag.prototype);
                    func_extended[group][key] = 1;
                }
            }
            return this;
        },
        removeGroupFuncs:function(group){
            if(!group)group = '_';
            if(group in func_extended){
                var groupFuncs = func_extended[group];
                for(var key in groupFuncs){
                    if(groupFuncs.hasOwnProperty(key)){
                        delete _tag.prototype[key];
                    }
                }
                delete func_extended[group];
            }
            return this;
        },
        removeAllFuncs:function(){
            for(var group in func_extended){
                if(func_extended.hasOwnProperty(group)){
                    var groupFuncs = func_extended[group];
                    for(var key in groupFuncs){
                        if(groupFuncs.hasOwnProperty(key)){
                            delete _tag.prototype[key];
                        }
                    }
                    delete func_extended[group];
                }
            }
            return this;
        },
        // -------- special attributes
        val: function(value){
            return this.attr({
                value:value
            });
        },
        width: function(width){
            return this.attr({
                width: width
            });
        },
        height: function(height){
            return this.attr({
                height: height
            });
        },
        src: function(src){
            return this.attr({
                src: src
            });
        },
        href: function(href){
            return this.attr({
                href:href
            });
        },
        rel:function(rel){
            return this.attr({
                rel:rel
            });
        },
        checked:function(checked){
            if(typeof checked == 'undefined') checked = true;
            if(checked){
                return this.attr('checked', '');
            } else {
                return this.removeAttr('checked');
            }
        },
        // -------- inputs
        Input: function(fullTagStr){
            return this._specTog(fullTagStr, 'input');
        },
        Hidden: function(fullTagStr, value){
            this._specTog(fullTagStr, 'input');
            this.type('hidden');
            if(value)this.val(value);
            return this;
        },
        Text: function(fullTagStr, value){
            this._specTog(fullTagStr, 'input');
            this.type('text');
            if(value)this.val(value);
            return this;
        },
        Button: function(fullTagStr, value){
            this._specTog(fullTagStr, 'input');
            this.type('button');
            if(value)this.val(value);
            return this;
        },
        Radio: function(fullTagStr, value, checked){
            this._specTog(fullTagStr, 'input');
            this.type('radio');
            if(value)this.val(value);
            if(checked)this.attr('checked', '');
            return this;
        },
        Check: function(fullTagStr, value, checked){
            this._specTog(fullTagStr, 'input');
            this.type('check');
            if(value)this.val(value);
            if(checked)this.attr('checked', '');
            return this;
        },
        // ---------- special
        cmt: function(comment){
            return this.cont('<!-- ', comment, '-->');
        },
        // ---------- tags
        Table: function(fullTagStr, attrs, content){
            return this._specTog(fullTagStr, 'table', attrs, content);
        },
        Tr: function(fullTagStr, attrs, content){
            return this._specTog(fullTagStr, 'tr', attrs, content);
        },
        Td: function(fullTagStr, attrs, content){
            return this._specTog(fullTagStr, 'td', attrs, content);
        },
        Textarea: function(fullTagStr, attrs, content){
            return this._specTog(fullTagStr, 'textarea', attrs, content);
        },
        Img: function(fullTagStr, src, attrs){
            this._specTog(fullTagStr, 'img', attrs);
            if(src){
                return this.src(src);
            }
            return this;
        },
        Div: function(fullTagStr, attrs, content){
            return this._specTog(fullTagStr, 'div', attrs, content);
        },
        Span: function(fullTagStr, attrs, content){
            return this._specTog(fullTagStr, 'span', attrs, content);
        },
        Script: function(fullTagStr, lang, href, content){
            this.curr = this._specTog(fullTagStr, 'script', null, content);
            if(lang) {
                this.attr({
                    language: lang
                });
            }
            else {
                this.attr({
                    language: 'text/javascript'
                });
            }
            if(href) this.href(href);
            return this;
        },
        Br: function(fullTagStr){
            return this._specTog(fullTagStr, 'br');
        },
        Hr: function(fullTagStr){
            return this._specTog(fullTagStr, 'hr');
        },
        Select: function(fullTagStr, attrs, content){
            return this._specTog(fullTagStr, 'select', attrs, content);
        },
        Option: function(fullTagStr, value, selected, attrs, content){
            this.curr = this._specTog(fullTagStr, 'option', attrs, content);
            if(value) this.val(value);
            if(selected) this.attr({
                selected: ''
            });
            return this;
        },
        Ul: function(fullTagStr, attrs, content){
            return this._specTog(fullTagStr, 'ul', attrs, content);
        },
        Il: function(fullTagStr, attrs, content){
            return this._specTog(fullTagStr, 'li', attrs, content);
        },
        A: function(fullTagStr, href, content, attrs){
            this.cursor = this._specTog(fullTagStr, 'a', attrs, content);
            if(href) return this.href(href);
            return this;
        },
        P: function(fullTagStr, content, attrs){
            return this._specTog(fullTagStr, 'p', attrs, content);
        },
        Body: function(fullTagStr, attrs, content){
            return this._specTog(fullTagStr, 'body', attrs, content);
        },
        Head: function(fullTagStr, attrs, content){
            return this._specTog(fullTagStr, 'head', attrs, content);
        },
        Font: function(fullTagStr, content, color, attrs){
            this._specTog(fullTagStr, 'font', attrs, content);
            if(color) return this.attr({
                color: color
            });
            return this;
        }
    } // end of _tag.prototype

    _tog.empty = new _tog('');
})()

function Tog(fullTagStr, attrs, content){
    var root = new _tog('');
    root._emp = 1;
    root._root = root;
    root._ids = {};
    root.curr = root;
    if(fullTagStr){
        root.Tog(fullTagStr, attrs, content);
    }
    return root;
}

